package com.zhoug.map3.location;

import android.annotation.SuppressLint;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Build;

import com.zhoug.common3.json.GsonUtils;
import com.zhoug.common3.Logger;
import com.zhoug.map3.Callback;
import com.zhoug.map3.Utils;
import com.zhoug.map3.dianditu.TianDiTuApi;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import androidx.annotation.NonNull;
import androidx.core.content.ContextCompat;

/**
 * gps位置服务
 * @Author: zhoug
 * @Date: 2025-01-07
 * @Description:
 */
public class GpsLocationService implements LocationService {
    private static final String TAG = ">>>GpsLocationService";
    private static final boolean DEBUG = false;
    private static final String KEY_LOCATION = "ZLocation";
    private LocationManager mLocationManager;
    private Context mContext;
    private final List<OnLocationListener> mListeners = new ArrayList<>(); //定位监听集合

    private final Set<String> locationSources = new HashSet<>();
    private SharedPreferences mSharedPreferences;

    /**
     * 位置更新最小时间间隔
     */
    private long mLocationUpdateMinTime = 0;
    /**
     * 位置更新最小移动距离
     */
    private float mLocationUpdateMinDistance = 0.0f;
    private boolean mIsStart = false;
    private ZLocation mLocation;//定位结果
    private ExecutorService executor = Executors.newSingleThreadExecutor();
    /**
     * 使用使用你地理编码获取详细的地址
     */
    private boolean mAddressEnable = false;
    /**
     * 获取详细的地址使用的api平台
     */
    private int mGeocoderType = GEOCODER_TYPE_TIANDITU;
    /**
     * 是否注册广播监听定位服务状态
     */
    private boolean mIsListenerProviderStatus;
    private String mProvider = null;


    public GpsLocationService(@NonNull Context context) {
        this.mContext = context;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            mLocationManager = mContext.getSystemService(LocationManager.class);
        } else {
            mLocationManager = (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
        }
        locationSources.add(LocationManager.GPS_PROVIDER);
        locationSources.add(LocationManager.NETWORK_PROVIDER);
        mSharedPreferences = context.getSharedPreferences("loc", Context.MODE_PRIVATE);

    }

    /**
     * 位置更新最小时间间隔
     *
     * @param locationUpdateMinTime
     */
    public void setLocationUpdateMinTime(long locationUpdateMinTime) {
        if (locationUpdateMinTime < 0) {
            this.mLocationUpdateMinTime = 0;
        } else {
            this.mLocationUpdateMinTime = locationUpdateMinTime;
        }
    }

    /**
     * 位置更新最小移动距离
     *
     * @param locationUpdateMinDistance
     */
    public void setLocationUpdateMinDistance(float locationUpdateMinDistance) {
        if (locationUpdateMinDistance < 0) {
            this.mLocationUpdateMinDistance = 0;
        } else {
            this.mLocationUpdateMinDistance = locationUpdateMinDistance;
        }
    }

    /**
     * 是否注册广播监听定位服务状态
     *
     * @param isListenerProviderStatus 默认 false
     */
    public void setListenerProviderStatus(boolean isListenerProviderStatus) {
        if (this.mIsListenerProviderStatus != isListenerProviderStatus) {
            unregisterBroadcastReceiver();
            if (isListenerProviderStatus) {
                registerBroadcastReceiver();
            }
            this.mIsListenerProviderStatus = isListenerProviderStatus;
        }
    }

    /**
     * GPS定位是否打开
     *
     * @return
     */
    public boolean isGpsOpen() {
        return Utils.isGpsOpen(mLocationManager);
    }


    /**
     * 启动定位sdk,启动后会默认立即发起定位请求
     */
    @SuppressLint("MissingPermission")
    @Override
    public void start() {
        if (mLocationManager != null) {
            mIsStart = true;
            _start();
        }
    }

    private void _start() {
        List<String> providers = mLocationManager.getProviders(true);
        if (providers.contains(LocationManager.GPS_PROVIDER)) {
            requestLocationUpdates(LocationManager.GPS_PROVIDER);
        } else if (providers.contains(LocationManager.NETWORK_PROVIDER)) {
            requestLocationUpdates(LocationManager.NETWORK_PROVIDER);
        } else {
            Logger.e(TAG, "GPS and NetWork provider all disabled");
        }
    }

    @SuppressLint("MissingPermission")
    private void requestLocationUpdates(String provider) {
        if (mLocationManager != null) {
            try {
                Logger.d(TAG, "start location:" + provider);
                mLocationManager.requestLocationUpdates(provider, mLocationUpdateMinTime,
                        mLocationUpdateMinDistance, mLocationListener);
                mProvider = provider;
            } catch (Throwable e) {
                Logger.e(TAG, "start location:" + e.getMessage());
            }
        }

    }

    /**
     * 停止定位sdk
     */
    @SuppressLint("MissingPermission")
    @Override
    public void stop() {
        mIsStart = false;
        if (mLocationManager != null && mProvider!=null) {
            if (DEBUG) {
                Logger.d(TAG, "stop location");
            }
            mProvider=null;
            try {
                mLocationManager.removeUpdates(mLocationListener);
            } catch (Exception e) {
                Logger.e(TAG, "stop location:" + e.getMessage());
            }
        }
    }


    /**
     * 使用自动通过经纬度获取地址信息
     *
     * @param addressEnable
     */
    @Override
    public void setAddressEnable(boolean addressEnable) {
        this.mAddressEnable = addressEnable;
    }

    /**
     * '
     * 设置使用哪个平台的API获取地址信息
     *
     * @param type 默认值{@link #GEOCODER_TYPE_TIANDITU}
     */
    @Override
    public void setGeocoderType(int type) {
        this.mGeocoderType = type;
    }

    /**
     * 获取最新的定位成功的位置:最后一次成功定位的位置或缓存的位置
     *
     * @return
     */
    @Override
    public ZLocation getLastLocation() {
        return getLocationFromDiskCache();
    }

    /**
     * 移除定位监听
     *
     * @param onLocationListener {@link OnLocationListener}
     */
    @Override
    public void removeOnLocationListener(OnLocationListener onLocationListener) {
        mListeners.remove(onLocationListener);

    }

    /**
     * 注册定位监听
     *
     * @param onLocationListener {@link OnLocationListener}
     */
    @Override
    public void addOnLocationListener(OnLocationListener onLocationListener) {
        if (!mListeners.contains(onLocationListener)) {
            mListeners.add(onLocationListener);
        }

    }

    /**
     * 销毁
     */
    @Override
    public void destroy() {
        unregisterBroadcastReceiver();
        stop();
        mListeners.clear();
        mLocationListener = null;
        mLocationManager = null;
        mContext = null;
        mSharedPreferences = null;
        mLocation = null;
    }

    /**
     * 位置更新回掉
     */
    private LocationListener mLocationListener = new LocationListener() {
        @Override
        public void onLocationChanged(@NonNull Location location) {
            if (mLocation == null) {
                mLocation = new ZLocation();
            }
            mLocation.setState(ZLocation.State.SUCCESS);
            if (DEBUG) {
                Logger.d(TAG, "onLocationChanged:location=" + location);
            }
            String provider = location.getProvider();
            mLocation.setLatLng(location.getLatitude(), location.getLongitude());
            if (LocationManager.GPS_PROVIDER.equals(provider)) {
                mLocation.setType(ZLocation.TypeGps);
            } else if (LocationManager.NETWORK_PROVIDER.equals(provider)) {
                mLocation.setType(ZLocation.TypeNetWork);
            } else {
                mLocation.setType(ZLocation.TypeCache);
            }
            mLocation.setAddress(null);
            if (mAddressEnable) {
                getAddress();
            } else {
                invokeCallback();
            }
        }


        @Override
        public void onProviderEnabled(@NonNull String provider) {
            if (DEBUG) {
                Logger.d(TAG, "onProviderEnabled:" + provider);
            }
        }


        @Override
        public void onProviderDisabled(@NonNull String provider) {
            if (DEBUG) {
                Logger.d(TAG, "onProviderDisabled:" + provider);
            }
        }
    };

    private void invokeCallback() {
        keepLocationToDiskCache(mLocation);
        //回掉注册的监听器
        if (!mListeners.isEmpty()) {
            for (OnLocationListener locationListener : mListeners) {
                if (locationListener != null) {
                    locationListener.onReceiveLocation(mLocation);
                }
            }
        }
    }

    private void getAddress() {
        double latitude = mLocation.getLatitude();
        double longitude = mLocation.getLongitude();
        IGeocoder iGeocoder;
        if (mGeocoderType == GEOCODER_TYPE_GOOGLE) {
            iGeocoder = new GeocoderHelper(mContext);
        } else {
            iGeocoder = TianDiTuApi.getInstance();
        }
        iGeocoder.geocoderReverse(latitude, longitude, new Callback<ZAddress>() {
            @Override
            public void onSuccess(ZAddress data) {
                mLocation.setAddress(data);
                invokeCallback();
            }

            @Override
            public void onFailure(String error) {
                invokeCallback();
            }
        });
    }

    /**
     * 缓存定位到xml
     */
    private void keepLocationToDiskCache(@NonNull ZLocation location) {
        if (executor != null && mSharedPreferences != null) {
            executor.execute(() -> {
                if (mSharedPreferences != null) {
                    SharedPreferences.Editor edit = mSharedPreferences.edit();
                    edit.putString(KEY_LOCATION, GsonUtils.getDefault().toJson(location));
                    edit.apply();
                }
            });
        }
    }

    /**
     * 从xml中获取缓存定位
     */
    private ZLocation getLocationFromDiskCache() {
        if (mSharedPreferences != null) {
            String string = mSharedPreferences.getString(KEY_LOCATION, null);
            if (string != null) {
                try {
                    ZLocation zLocation = GsonUtils.getDefault().fromJson(string, ZLocation.class);
                    if(zLocation!=null){
                        zLocation.setType(ZLocation.TypeCache);
                    }
                    return zLocation;
                } catch (Exception e) {
                    Logger.e(TAG, "getLocationFromDiskCache:" + e.getMessage());
                }
            }
        }
        return null;
    }

    /**
     * 注册广播
     */
    private void registerBroadcastReceiver() {
        IntentFilter filter = new IntentFilter();
        filter.addAction(LocationManager.PROVIDERS_CHANGED_ACTION);
        ContextCompat.registerReceiver(mContext, mLocationProviderReceiver, filter, ContextCompat.RECEIVER_EXPORTED);
    }

    /**
     * 取消注册广播
     */
    private void unregisterBroadcastReceiver() {
        if (mIsListenerProviderStatus) {
            mContext.unregisterReceiver(mLocationProviderReceiver);
        }
    }

    /**
     * 定位服务状态监听广播
     * 开启定位后根据状态自动调用定位服务
     */
    private final BroadcastReceiver mLocationProviderReceiver = new BroadcastReceiver() {

        @SuppressLint("MissingPermission")
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (LocationManager.PROVIDERS_CHANGED_ACTION.equals(action)) {
                //监听GPS服务状态 重庆启动定位服务
                if (mIsStart && mLocationManager != null) {
                    Logger.d(TAG, "onReceive:GPS服务状态改变");
                    if(mProvider==null){
                        _start();
                    }else{
                        List<String> providers = mLocationManager.getProviders(true);
                        if (DEBUG) {
                            Logger.d(TAG, "onReceive:enable providers:"+GsonUtils.getDefault().toJson(providers));
                        }
                        if(!providers.contains(mProvider)){
                            if (DEBUG) {
                                Logger.d(TAG, "onReceive:移除:"+mProvider);
                            }
                            mProvider=null;
                            try {
                                mLocationManager.removeUpdates(mLocationListener);
                            } catch (Exception e) {
                               Logger.e(TAG, "onReceive:"+e.getMessage());
                            }
                        }
                        if(mProvider==null && !providers.isEmpty()){
                            _start();
                        }
                    }
                }

            }
        }
    };

}
